<!--
 * Automated tests for jwt-js, pure JavaScript implementation of JSON Web Tokens.
 * Copyright (c) 2011, Michael Hanson, mhanson@mozilla.com
 * See README for licensing data.
 *
 * Based on and translated from Java-based unit tests for WebTokenTests by AxelNennker,
 * license notice follows:
 *
 * Copyright (c) 2011, Axel Nennker - http://axel.nennker.de/
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the names xmldap, xmldap.org, xmldap.com nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->

<html>
<head>
<title>JSON Web Token Tests</title>
<script type="text/javascript" src="../build/jwt.js"></script>
<script type="text/javascript" src="doctest/doctest.js"></script>
<!-- This stylesheet is optional, but does improve the output: -->
<link rel="stylesheet" type="text/css" href="doctest/doctest.css" />
<style type="text/css">
body {
  font-family: sans-serif;
}
</style>
<script>
/* Some shared objects for tests: */
var joeStr = "{\"iss\":\"joe\",\r\n" + " \"exp\":1300819380,\r\n" + " \"http://example.com/is_root\":true}";
var hs256 = "{\"typ\":\"JWT\",\r\n"+
                 " \"alg\":\"HS256\"}";
var hs384 = "{\"typ\":\"JWT\",\r\n"+
                 " \"alg\":\"HS384\"}";
var hs512 = "{\"typ\":\"JWT\",\r\n"+
                 " \"alg\":\"HS512\"}";

var hsKey = [3, 35, 53, 75, 43, 15, 165, 188, 131, 126, 6, 101, 119, 123, 166, 143, 90, 179, 40, 230, 240, 84, 201, 40, 169, 15, 132, 178, 210, 80, 46, 191, 211, 251, 90, 146, 210, 6, 71, 239, 150, 138, 180, 195, 119, 98, 61, 34, 61, 46, 33, 114, 5, 46, 79, 8, 192, 205, 154, 245, 103, 208, 128, 163];
var rsKeyPEM = window.atob("LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBeEV5bWpsbVBNVXN2RTVQVStBVFNOd2c0dkxtS2tEMzFTRzI4WkRuN0RoNmMxT0FoCllYL3lFcCs1QlhxOHliQmtScGZDLzdzclJRNCtUeG5uR3NwUHQvZVF5S2ZORjgwbHd5NFRSQS9TYlJDallmK04KVHE2ZTh2M1FIOE05U2NpS01HME9MbXZNbk9nVi9tVFJVd1pTdUxPZXRaTEQxNmdDZ2QxR0cwc01BS0JYYkpaZwoyb3oxdEp1bFBPdGFDWW1ReHU1M2NWSGtmRHZGLzRLMG1LMTIyam8xRnh4UGtBbjNOcU1Db2QzR3hpOFVIaE5iCjBzOHhsVzl6Ynlvc2RmdGJqOWI1VGRCTXBSUzlmRWllc1psQVpxOGtPa1lUUnJVVHJZdjI1d2pYaEhCSGNOeUsKVEhDbjVYZGl2dTdzZFBMZVBEajhuSFJuTGo0cmtTaktwaUZHYXdJREFRQUJBb0lCQVFDZDVib2p6czVyckRwVgoyUmY1MklidlZXR3VET0QwWGFJcmZIbUpkVW9JZFg5WmpGL05lWWxTaWIvZU5IZ2ZGQS9VNk1ZbHhueHJzNlZUCkkxYk9LZVl0NktsQmZoaHZDTWxUVW9DVXd0VlVmWW11amswditTNUo3dmUyVk9tN3E5L2NUQnlZSW9ZWHdHZlEKbFcvN0JKOE5pdzRpcDhkNGRPQnZiWG16QW83SkFNZERBTXdDZlNPTFBwRVprMXdsc1Q5YjBHaHZnMHZsVU5oTwpISGRmSjYzRlRyY2xZUFZETXNuNmU1aEZOSXRCenVQeDlvUjN2eENmQjQyZkY5TVpYRnpIamx0NUd1Q0hqOUN0CkJ4UlJxdENsb1JLR3V1ak9DUkEzM1NaS3p3Snd2KzkzZkxZVkh0anBYOGsvczhjYkpFcFVzdDlxdGxZTmoxSFoKMmc2Q0t0QkJBb0dCQVBEQ0o4R20wYjQ2Y0FiLzY3MXMxeFJJYnRDbjZxSEtwVHFwN1RJT2FxajlOQWJqeDFrYgozTUJ1MUc4OVZzMFRvOWlZejB2M1VZcUMyZ0kzTnd2SEtZZTBReENaVE84Y2kvaVRxa3ZsbXZNbG1XK2ZwQnlRCmhzay8vTXMzQlcvM0VNRVhiUklLNXA3akFMa2ZyemVqY0pIeG5scTkzdlJob2lSZUsrMWVqTEVqQW9HQkFOQzUKK01HNU5wZnJjaUR0akhQelp5YlRUd0t2b0wzVEpvMWNESHJaaE5nWWNUOTgrSkM1bzcwWTIvSXprcHZPUmFuagpiUEIrcEhFM2ZYZ0dHVHFESGNtbyt2RnQ4MkZvRGVMdmRRb0NJblduMzJtTUlvQUthdE8zM3oreUFmcjg2eUZOCjIzdlNQL0JndXBrVEYvZ0ltY3QvK2tlWU12WDB6KzhsUVR6eUpMNFpBb0dBVldhWmthQ3AvODljMDY3T0lXaE4KTnIybXlVNzI5S01jVHgzZHJJYmVvTWtJUG5WbnpoMExCaHVLTVZkUnhmYjBoSzFYd3Z1Y3FnUldicmpGUnVGRAp3d1pYVDdrQlNFUVpCbmppekg5S29uc3czUjZFcVRrL0JuNHpIcWFLd0Rla2NzbnJmNTNzUm1vQlpLbHZqczNqCjdYRUdtZXVGL2F2d1J2UThvcnVLTG44Q2dZQTM0b01yQXpjTngvbGZ2WnFNZFJBYVFodDJnYVdORFpyVjRGNXIKQ2hCYWQzamk0Y2YvbitTcVBaeXVKWWJNZHBjS1hKMFBheWtHTXpCQjBZZ3h0V2RsVmZ3U1pqanl6SlJqUFcvZAp4U0tLMCs2cWFOM1g0SElueTZSWGZvYXZOOGFRdlRMVjNUNUhVdTdEQzJ5d2VVVU1TbkN0ZUorMFlON0hqZmNBCnBXaVhDUUtCZ0N5SDVETTFWb1NNaCtVSXJ6WW5vVVVKY1ZDL3EyWGp0Zkdod3JhVUJhTTZ6OVNXaFg2amZMSGkKNW9qc2ZjSE5vU3h5a0hJQllXNmovQ1ZVSmpoY2NRa0pnR2tHRmoxZkh2cTVpWGZPaTFjMWl6djQxQ0REWGRQKwpKcTNNbHMzaDVXTnJ5RTdhTTQ5S3JaRWpjbytzajVRc3dMMnkwTk1weHdHRE9palpqS0lyCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==")
var rsPubKeyPEM = window.atob("LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF4RXltamxtUE1Vc3ZFNVBVK0FUUwpOd2c0dkxtS2tEMzFTRzI4WkRuN0RoNmMxT0FoWVgveUVwKzVCWHE4eWJCa1JwZkMvN3NyUlE0K1R4bm5Hc3BQCnQvZVF5S2ZORjgwbHd5NFRSQS9TYlJDallmK05UcTZlOHYzUUg4TTlTY2lLTUcwT0xtdk1uT2dWL21UUlV3WlMKdUxPZXRaTEQxNmdDZ2QxR0cwc01BS0JYYkpaZzJvejF0SnVsUE90YUNZbVF4dTUzY1ZIa2ZEdkYvNEswbUsxMgoyam8xRnh4UGtBbjNOcU1Db2QzR3hpOFVIaE5iMHM4eGxXOXpieW9zZGZ0Ymo5YjVUZEJNcFJTOWZFaWVzWmxBClpxOGtPa1lUUnJVVHJZdjI1d2pYaEhCSGNOeUtUSENuNVhkaXZ1N3NkUExlUERqOG5IUm5MajRya1NqS3BpRkcKYXdJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==");
var rsPubKeyModulus = "C44CA68E598F314B2F1393D4F804D2370838BCB98A903DF5486DBC6439FB0E1E9CD4E021617FF2129FB9057ABCC9B0644697C2FFBB2B450E3E4F19E71ACA4FB7F790C8A7CD17CD25C32E13440FD26D10A361FF8D4EAE9EF2FDD01FC33D49C88A306D0E2E6BCC9CE815FE64D1530652B8B39EB592C3D7A80281DD461B4B0C00A0576C9660DA8CF5B49BA53CEB5A098990C6EE777151E47C3BC5FF82B498AD76DA3A35171C4F9009F736A302A1DDC6C62F141E135BD2CF31956F736F2A2C75FB5B8FD6F94DD04CA514BD7C489EB1994066AF243A461346B513AD8BF6E708D784704770DC8A4C70A7E57762BEEEEC74F2DE3C38FC9C74672E3E2B9128CAA621466B";
var rsPubKeyExponent = "10001";


var es256 = "{\"alg\":\"ES256\"}";
var es384 = "{\"alg\":\"ES384\"}";
var es512 = "{\"alg\":\"ES512\"}";

var rs256 = "{\"alg\":\"RS256\"}";
var rs384 = "{\"alg\":\"RS384\"}";
var rs512 = "{\"alg\":\"RS512\"}";

var hmacKey = "hmackey"
var sampleHS256 = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.AF9JZKWRn2omJDrJrWeoVQyjR3PcGFiAe0_dC04hwyE";
var sampleRS256 = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.PD3-BJR3UrF6del98ffZ8d8Vu3RMLhqj117r6LQNpM5eMImCKarEpqf6j1cu2FZZ9zQzusXPkBYPTUE1SKg8lzJmHbgSAaSunxxprS_XNYbFg8y9twxYBHh3umyJ0JTBWx5OciLQuapX8fKCZXINUXl1ytR1CCw4tSwD3ekMddLlAkmqdn7gYpIswaAO7bMOqrszXM5QAh7AMCwoisFBvUDFCrzs0alLIcPButn6vXo0p7vhakXXUPy7vRgTMsf3kSJcvJzLtxlcV0K1LiiR3wR_dcxSeRNkm075uIggTmSXhtUm7cswEr1u5YVN7F2v1pjg_KYwnhtRkP8AGU-k9g";


function assert(x) 
{
  if (!x) throw "AssertionFailure";
}

</script>
</head>

<body class="autodoctest">
<!-- the autotest class tells doctest to run the tests and fill
in extra elements automatically -->

<h1>JSON Web Token tests</h1>
<div class="test">
</div>

<h2>Test Encodings</h2>
<div class="test">
A simple JSON object is correctly converted to Base64url.
<pre class="doctest">
$ jwt.base64urlencode(joeStr); // note absence of padding == at end of string
"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
$ jwt.base64urldecode(jwt.base64urlencode(joeStr)) == joeStr;
true
</pre>
<!-- // to test: does this properly handle high-byte characters? -->
</div>

<div class="test">
An HS256 algorithm element is correctly converted to Base64url.
<pre class="doctest">
$ jwt.base64urlencode(hs256);
"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9"
</pre>
</div>

<div class="test">
An ES256 algorithm element is correctly converted to Base64url.
<pre class="doctest">
$ jwt.base64urlencode(es256);
"eyJhbGciOiJFUzI1NiJ9"
</pre>
</div>

<div class="test">
An RS256 algorithm element is correctly converted to Base64url.
<pre class="doctest">
$ jwt.base64urlencode(rs256);
"eyJhbGciOiJSUzI1NiJ9"
</pre>
</div>

<h2>Test Digest Functions</h2>

<div class="test">
SHA256 implementation appears to be correct:
<pre class="doctest">
$ sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash("Hello World"));
"a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"
$ sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
"d6ec6898de87ddac6e5b3611708a7aa1c2d298293349cc1a6c299a1db7149d38"
$ sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890./="));
"f250c33ac399835034a17e00afcc2fae03fd90389eef40f11e5123f154e1f9ca"
</pre>
</div>



<h2>Test Signature Generation</h2>

<div class="test">
Test creation of an HMAC-SHA256 signature.
<pre class="doctest">
$ var token = new jwt.WebToken(joeStr, hs256);
$ var signed = token.serialize(hmacKey)
$ var split = signed.split("\.")
$ split.length
3
$ split[0]
"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9"
$ split[1]
"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
$ split[2] // correct value generated by OpenSSL; see make_samples.sh
"AF9JZKWRn2omJDrJrWeoVQyjR3PcGFiAe0_dC04hwyE"
</pre>
</div>


<div class="test">
Test creation of an RSA-SHA256 signature.
<pre class="doctest">
$ var token = new jwt.WebToken(joeStr, rs256);
$ var signed = token.serialize(rsKeyPEM)
$ var split = signed.split("\.")
$ split.length
3
$ split[0]
"eyJhbGciOiJSUzI1NiJ9"
$ split[1]
"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
$ split[2] // correct value generated by OpenSSL; see make_samples.sh
"PD3-BJR3UrF6del98ffZ8d8Vu3RMLhqj117r6LQNpM5eMImCKarEpqf6j1cu2FZZ9zQzusXPkBYPTUE1SKg8lzJmHbgSAaSunxxprS_XNYbFg8y9twxYBHh3umyJ0JTBWx5OciLQuapX8fKCZXINUXl1ytR1CCw4tSwD3ekMddLlAkmqdn7gYpIswaAO7bMOqrszXM5QAh7AMCwoisFBvUDFCrzs0alLIcPButn6vXo0p7vhakXXUPy7vRgTMsf3kSJcvJzLtxlcV0K1LiiR3wR_dcxSeRNkm075uIggTmSXhtUm7cswEr1u5YVN7F2v1pjg_KYwnhtRkP8AGU-k9g"</pre>
</div>

<div class="test">
RSA-SHA384 is unsupported.
<pre class="doctest">
$ var token = new jwt.WebToken(joeStr, rs384);
$ token.serialize(rsKeyPEM);
Error: RSA-SHA384 not yet implemented
</pre>
</div>

<div class="test">
RSA-SHA512 is unsupported.
<pre class="doctest">
$ var token = new jwt.WebToken(joeStr, rs512);
$ token.serialize(rsKeyPEM);
Error: RSA-SHA512 not yet implemented
</pre>
</div>

<div class="test">
HMAC-SHA384 is unsupported.
<pre class="doctest">
$ var token = new jwt.WebToken(joeStr, hs384);
$ token.serialize(hmacKey);
Error: HMAC-SHA384 not yet implemented
</pre>
</div>

<div class="test">
HMAC-SHA512 is unsupported.
<pre class="doctest">
$ var token = new jwt.WebToken(joeStr, hs512);
$ token.serialize(hmacKey);
Error: HMAC-SHA512 not yet implemented
</pre>
</div>


<div class="test">
ECDSA-SHA384 is unsupported.
<pre class="doctest">
$ var token = new jwt.WebToken(joeStr, es384);
$ token.serialize(hmacKey);
Error: ECDSA-SHA384 not yet implemented
</pre>
</div>

<div class="test">
ECDSA-SHA512 is unsupported.
<pre class="doctest">
$ var token = new jwt.WebToken(joeStr, es512);
$ token.serialize(hmacKey);
Error: ECDSA-SHA512 not yet implemented
</pre>
</div>

<h2>Test Signature Verification</h2>

<div class="test">
Test verification of an HMAC-SHA256 signature.
<pre class="doctest">
$ var token = jwt.WebTokenParser.parse(sampleHS256);
$ token.verify(hmacKey)
true
</pre>
</div>

<div class="test">
Test verification of an RSA-SHA256 signature.
<pre class="doctest">
$ var token = jwt.WebTokenParser.parse(sampleRS256);
$ var pubKey = new RSAKey();
$ pubKey.setPublic(rsPubKeyModulus, rsPubKeyExponent);
$ token.verify(pubKey)
true
</pre>
</div>
  

<div class="test">
Test verification of an EDSA Signature according to Draft 01.
<pre class="doctest">
$ var ec256Token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q";
$ var x = [127, 205, 206, 39, 112, 246, 196, 93, 65, 131, 203, 238, 111, 219, 75, 123, 88, 7, 51, 53, 123, 233, 239, 19, 186, 207, 110, 60, 123, 209, 84, 69];
$ var y = [199, 241, 68, 205, 27, 189, 155, 126, 135, 44, 223, 237, 185, 238, 185, 244, 179, 105, 93, 110, 169, 11, 36, 173, 138, 70, 35, 40, 133, 136, 229, 173];
$ var token = jwt.WebTokenParser.parse(ec256Token);
$ token.verify(x, y);
true
</pre>
</div>

<!--

  public void testEDSAsignature_Draft01() 
  throws Exception {
    String signature = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q";
    byte[] x = {127, (byte)205, (byte)206, (byte)39, (byte)112, (byte)246, (byte)196, (byte)93, (byte)65, (byte)131, (byte)203, (byte)238, (byte)111, (byte)219, (byte)75, (byte)123, (byte)88, (byte)7, (byte)51, (byte)53, (byte)123, (byte)233, (byte)239, (byte)19, (byte)186, (byte)207, (byte)110, (byte)60, (byte)123, (byte)209, (byte)84, (byte)69};
    byte[] y = {(byte)199, (byte)241, (byte)68, (byte)205, (byte)27, (byte)189, (byte)155, (byte)126, (byte)135, (byte)44, (byte)223, (byte)237, (byte)185, (byte)238, (byte)185, (byte)244, (byte)179, (byte)105, (byte)93, (byte)110, (byte)169, (byte)11, (byte)36, (byte)173, (byte)138, (byte)70, (byte)35, (byte)40, (byte)133, (byte)136, (byte)229, (byte)173};

    assertTrue(WebToken.verify(signature, x, y));
  }
  
  public void testEDSAsignature() 
  throws Exception {
//    byte[] x = {48, (byte)160, 66, 76, (byte)210, 28, 41, 68, (byte)131, (byte)138, 45, 117, (byte)201, 43, 55, (byte)231, 110, (byte)162, 13, (byte)159, 0, (byte)137, 58, 59, 78, (byte)238, (byte)138, 60, 10, (byte)175, (byte)236, 62};
//    byte[] y = {(byte)224, 75, 101, (byte)233, 36, 86, (byte)217, (byte)136, (byte)139, 82, (byte)179, 121, (byte)189, (byte)251, (byte)213, 30, (byte)232, 105, (byte)239, 31, 15, (byte)198, 91, 102, 89, 105, 91, 108, (byte)206, 8, 23, 35};
    byte[] d = {(byte)243, (byte)189, 12, 7, (byte)168, 31, (byte)185, 50, 120, 30, (byte)213, 39, 82, (byte)246, 12, (byte)200, (byte)154, 107, (byte)229, (byte)229, 25, 52, (byte)254, 1, (byte)147, (byte)141, (byte)219, 85, (byte)216, (byte)247, 120, 1};
    
//    "secp256r1 [NIST P-256, X9.62 prime256v1]", "1.2.840.10045.3.1.7"
    WebToken wt = new WebToken(joeStr, es256);
    String signed = wt.serialize(new BigInteger(1,d));
    String[] split = signed.split("\\.");
    assertEquals(3, split.length);
    assertEquals("eyJhbGciOiJFUzI1NiJ9", split[0]);
    assertEquals("eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ", split[1]);
    byte[] signatureBytes = Base64.decodeUrl(split[2]);
    assertEquals(64, signatureBytes.length);
    byte[] x = {48, (byte)160, 66, 76, (byte)210, 28, 41, 68, (byte)131, (byte)138, 45, 117, (byte)201, 43, 55, (byte)231, 110, (byte)162, 13, (byte)159, 0, (byte)137, 58, 59, 78, (byte)238, (byte)138, 60, 10, (byte)175, (byte)236, 62};
    byte[] y = {(byte)224, 75, 101, (byte)233, 36, 86, (byte)217, (byte)136, (byte)139, 82, (byte)179, 121, (byte)189, (byte)251, (byte)213, 30, (byte)232, 105, (byte)239, 31, 15, (byte)198, 91, 102, 89, 105, 91, 108, (byte)206, 8, 23, 35};
    assertTrue(WebToken.verify(signed, x, y));

  }
  
  private void testHMACSHA(
      String jwtAlgorithm, String jwtHeaderSegment, String jwtCryptoSegment) 
  throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, JSONException {
    WebToken jwt = new WebToken(joeStr, jwtAlgorithm);
    String signed = jwt.serialize(hsKey);
    String[] split = signed.split("\\.");
    assertEquals(3, split.length);
    assertEquals(jwtHeaderSegment, split[0]);
    assertEquals("eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ", split[1]);
    assertEquals(jwtCryptoSegment, split[2]);
    String expected = split[0] + "." + split[1] + "." + split[2];
    assertEquals(expected, signed);
  }
  
  public void testHS256() throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, JSONException {
    testHMACSHA(hs256, "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9", "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"); 
  }

  public void testHS384() throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, JSONException {
    testHMACSHA(hs384, "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzM4NCJ9", 
        "TUfcA4Xjq_veopvw1fiFG99UswFSMvxYisxxBb0kHQ7w8He3OkvmELPo0uy3RuR0"); 
  }
  
  public void testHS512() throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, JSONException {
    testHMACSHA(hs512, "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzUxMiJ9", 
        "iXxB-yPnHRvriuSAfTrwz-gr5WYC6tg7gIq9JndRI9Uqn4D6twBgsJuQsQks6WqAC6OB23Lvdht79p_lA6jE8g"); 
  }
  
-->



</body> </html>


<!--

public class WebTokenTest extends TestCase {
  JSONObject joeO = null;

  String joeStr = "{\"iss\":\"joe\",\r\n" +
      " \"exp\":1300819380,\r\n" +
      " \"http://example.com/is_root\":true}";
  
  String hs256 = "{\"typ\":\"JWT\",\r\n"+
                 " \"alg\":\"HS256\"}";
  String hs384 = "{\"typ\":\"JWT\",\r\n"+
                 " \"alg\":\"HS384\"}";
  String hs512 = "{\"typ\":\"JWT\",\r\n"+
                 " \"alg\":\"HS512\"}";
  byte[] hsKey = {3, (byte)35, (byte)53, (byte)75, (byte)43, (byte)15, (byte)165, (byte)188, (byte)131, (byte)126, (byte)6, (byte)101, (byte)119, (byte)123, (byte)166, (byte)143, (byte)90, (byte)179, (byte)40, (byte)230, (byte)240, (byte)84, (byte)201, (byte)40, (byte)169, (byte)15, (byte)132, (byte)178, (byte)210, (byte)80, (byte)46, (byte)191, (byte)211, (byte)251, (byte)90, (byte)146, (byte)210, (byte)6, (byte)71, (byte)239, (byte)150, (byte)138, (byte)180, (byte)195, (byte)119, (byte)98, (byte)61, (byte)34, (byte)61, (byte)46, (byte)33, (byte)114, (byte)5, (byte)46, (byte)79, (byte)8, (byte)192, (byte)205, (byte)154, (byte)245, (byte)103, (byte)208, (byte)128, (byte)163};
  
  String es256 = "{\"alg\":\"ES256\"}";
  String es384 = "{\"alg\":\"ES384\"}";
  String es512 = "{\"alg\":\"ES512\"}";

  String rs256 = "{\"alg\":\"RS256\"}";
  String rs384 = "{\"alg\":\"RS384\"}";
  String rs512 = "{\"alg\":\"RS512\"}";
  
  public void setUp() {
    try {
      super.setUp();
    } catch (Exception e) {
      assertTrue(false);
    }
  }

  public void testJoeEncoding() throws UnsupportedEncodingException {
    byte[] bytes = joeStr.getBytes("utf-8");
    String base64urlStr = Base64.encodeBytes(bytes, 
        org.xmldap.util.Base64.DONT_BREAK_LINES | org.xmldap.util.Base64.URL);
    String expected = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ";
    assertEquals(expected, base64urlStr);
  }

  public void testHS256Encoding() throws UnsupportedEncodingException {
    byte[] bytes = hs256.getBytes("utf-8");
    String base64urlStr = Base64.encodeBytes(bytes, 
        org.xmldap.util.Base64.DONT_BREAK_LINES | org.xmldap.util.Base64.URL);
    String expected = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9";
    assertEquals(expected, base64urlStr);
  }

  public void testES256Encoding() throws UnsupportedEncodingException {
    byte[] bytes = es256.getBytes("utf-8");
    String base64urlStr = Base64.encodeBytes(bytes, 
        org.xmldap.util.Base64.DONT_BREAK_LINES | org.xmldap.util.Base64.URL);
    String expected = "eyJhbGciOiJFUzI1NiJ9";
    assertEquals(expected, base64urlStr);
  }

//  public void testProviders() {
//    Security.addProvider(new BouncyCastleProvider());
//    Provider[] providers = java.security.Security.getProviders();
//    for (int i=0; i<providers.length; i++) {
//      Provider p = providers[i];
//      System.out.println(p.getName());
//    }
//  }
  
  public void testEDSAsignature_Draft01() 
  throws Exception {
    String signature = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q";
    byte[] x = {127, (byte)205, (byte)206, (byte)39, (byte)112, (byte)246, (byte)196, (byte)93, (byte)65, (byte)131, (byte)203, (byte)238, (byte)111, (byte)219, (byte)75, (byte)123, (byte)88, (byte)7, (byte)51, (byte)53, (byte)123, (byte)233, (byte)239, (byte)19, (byte)186, (byte)207, (byte)110, (byte)60, (byte)123, (byte)209, (byte)84, (byte)69};
    byte[] y = {(byte)199, (byte)241, (byte)68, (byte)205, (byte)27, (byte)189, (byte)155, (byte)126, (byte)135, (byte)44, (byte)223, (byte)237, (byte)185, (byte)238, (byte)185, (byte)244, (byte)179, (byte)105, (byte)93, (byte)110, (byte)169, (byte)11, (byte)36, (byte)173, (byte)138, (byte)70, (byte)35, (byte)40, (byte)133, (byte)136, (byte)229, (byte)173};

    assertTrue(WebToken.verify(signature, x, y));
  }
  
  public void testEDSAsignature() 
  throws Exception {
//    byte[] x = {48, (byte)160, 66, 76, (byte)210, 28, 41, 68, (byte)131, (byte)138, 45, 117, (byte)201, 43, 55, (byte)231, 110, (byte)162, 13, (byte)159, 0, (byte)137, 58, 59, 78, (byte)238, (byte)138, 60, 10, (byte)175, (byte)236, 62};
//    byte[] y = {(byte)224, 75, 101, (byte)233, 36, 86, (byte)217, (byte)136, (byte)139, 82, (byte)179, 121, (byte)189, (byte)251, (byte)213, 30, (byte)232, 105, (byte)239, 31, 15, (byte)198, 91, 102, 89, 105, 91, 108, (byte)206, 8, 23, 35};
    byte[] d = {(byte)243, (byte)189, 12, 7, (byte)168, 31, (byte)185, 50, 120, 30, (byte)213, 39, 82, (byte)246, 12, (byte)200, (byte)154, 107, (byte)229, (byte)229, 25, 52, (byte)254, 1, (byte)147, (byte)141, (byte)219, 85, (byte)216, (byte)247, 120, 1};
    
//    "secp256r1 [NIST P-256, X9.62 prime256v1]", "1.2.840.10045.3.1.7"
    WebToken wt = new WebToken(joeStr, es256);
    String signed = wt.serialize(new BigInteger(1,d));
    String[] split = signed.split("\\.");
    assertEquals(3, split.length);
    assertEquals("eyJhbGciOiJFUzI1NiJ9", split[0]);
    assertEquals("eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ", split[1]);
    byte[] signatureBytes = Base64.decodeUrl(split[2]);
    assertEquals(64, signatureBytes.length);
    byte[] x = {48, (byte)160, 66, 76, (byte)210, 28, 41, 68, (byte)131, (byte)138, 45, 117, (byte)201, 43, 55, (byte)231, 110, (byte)162, 13, (byte)159, 0, (byte)137, 58, 59, 78, (byte)238, (byte)138, 60, 10, (byte)175, (byte)236, 62};
    byte[] y = {(byte)224, 75, 101, (byte)233, 36, 86, (byte)217, (byte)136, (byte)139, 82, (byte)179, 121, (byte)189, (byte)251, (byte)213, 30, (byte)232, 105, (byte)239, 31, 15, (byte)198, 91, 102, 89, 105, 91, 108, (byte)206, 8, 23, 35};
    assertTrue(WebToken.verify(signed, x, y));

  }
  
  private void testHMACSHA(
      String jwtAlgorithm, String jwtHeaderSegment, String jwtCryptoSegment) 
  throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, JSONException {
    WebToken jwt = new WebToken(joeStr, jwtAlgorithm);
    String signed = jwt.serialize(hsKey);
    String[] split = signed.split("\\.");
    assertEquals(3, split.length);
    assertEquals(jwtHeaderSegment, split[0]);
    assertEquals("eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ", split[1]);
    assertEquals(jwtCryptoSegment, split[2]);
    String expected = split[0] + "." + split[1] + "." + split[2];
    assertEquals(expected, signed);
  }
  
  public void testHS256() throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, JSONException {
    testHMACSHA(hs256, "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9", "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"); 
  }

  public void testHS384() throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, JSONException {
    testHMACSHA(hs384, "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzM4NCJ9", 
        "TUfcA4Xjq_veopvw1fiFG99UswFSMvxYisxxBb0kHQ7w8He3OkvmELPo0uy3RuR0"); 
  }
  
  public void testHS512() throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, JSONException {
    testHMACSHA(hs512, "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzUxMiJ9", 
        "iXxB-yPnHRvriuSAfTrwz-gr5WYC6tg7gIq9JndRI9Uqn4D6twBgsJuQsQks6WqAC6OB23Lvdht79p_lA6jE8g"); 
  }
  
  private void testRSASHA(
      String jwtAlgorithm, String jwtHeaderSegment, String jwtCryptoSegment) 
  throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException, JSONException, IOException {
    WebToken jwt = new WebToken(joeStr, jwtAlgorithm);
    byte[] n = {(byte)161, (byte)248, (byte)22, (byte)10, (byte)226, (byte)227, (byte)201, (byte)180, (byte)101, (byte)206, (byte)141, (byte)45, (byte)101, (byte)98, (byte)99, (byte)54, (byte)43, (byte)146, (byte)125, (byte)190, (byte)41, (byte)225, (byte)240, (byte)36, (byte)119, (byte)252, (byte)22, (byte)37, (byte)204, (byte)144, (byte)161, (byte)54, (byte)227, (byte)139, (byte)217, (byte)52, (byte)151, (byte)197, (byte)182, (byte)234, (byte)99, (byte)221, (byte)119, (byte)17, (byte)230, (byte)124, (byte)116, (byte)41, (byte)249, (byte)86, (byte)176, (byte)251, (byte)138, (byte)143, (byte)8, (byte)154, (byte)220, (byte)75, (byte)105, (byte)137, (byte)60, (byte)193, (byte)51, (byte)63, (byte)83, (byte)237, (byte)208, (byte)25, (byte)184, (byte)119, (byte)132, (byte)37, (byte)47, (byte)236, (byte)145, (byte)79, (byte)228, (byte)133, (byte)119, (byte)105, (byte)89, (byte)75, (byte)234, (byte)66, (byte)128, (byte)211, (byte)44, (byte)15, (byte)85, (byte)191, (byte)98, (byte)148, (byte)79, (byte)19, (byte)3, (byte)150, (byte)188, (byte)110, (byte)155, (byte)223, (byte)110, (byte)189, (byte)210, (byte)189, (byte)163, (byte)103, (byte)142, (byte)236, (byte)160, (byte)198, (byte)104, (byte)247, (byte)1, (byte)179, (byte)141, (byte)191, (byte)251, (byte)56, (byte)200, (byte)52, (byte)44, (byte)226, (byte)254, (byte)109, (byte)39, (byte)250, (byte)222, (byte)74, (byte)90, (byte)72, (byte)116, (byte)151, (byte)157, (byte)212, (byte)185, (byte)207, (byte)154, (byte)222, (byte)196, (byte)199, (byte)91, (byte)5, (byte)133, (byte)44, (byte)44, (byte)15, (byte)94, (byte)248, (byte)165, (byte)193, (byte)117, (byte)3, (byte)146, (byte)249, (byte)68, (byte)232, (byte)237, (byte)100, (byte)193, (byte)16, (byte)198, (byte)182, (byte)71, (byte)96, (byte)154, (byte)164, (byte)120, (byte)58, (byte)235, (byte)156, (byte)108, (byte)154, (byte)215, (byte)85, (byte)49, (byte)48, (byte)80, (byte)99, (byte)139, (byte)131, (byte)102, (byte)92, (byte)111, (byte)111, (byte)122, (byte)130, (byte)163, (byte)150, (byte)112, (byte)42, (byte)31, (byte)100, (byte)27, (byte)130, (byte)211, (byte)235, (byte)242, (byte)57, (byte)34, (byte)25, (byte)73, (byte)31, (byte)182, (byte)134, (byte)135, (byte)44, (byte)87, (byte)22, (byte)245, (byte)10, (byte)248, (byte)53, (byte)141, (byte)154, (byte)139, (byte)157, (byte)23, (byte)195, (byte)64, (byte)114, (byte)143, (byte)127, (byte)135, (byte)216, (byte)154, (byte)24, (byte)216, (byte)252, (byte)171, (byte)103, (byte)173, (byte)132, (byte)89, (byte)12, (byte)46, (byte)207, (byte)117, (byte)147, (byte)57, (byte)54, (byte)60, (byte)7, (byte)3, (byte)77, (byte)111, (byte)96, (byte)111, (byte)158, (byte)33, (byte)224, (byte)84, (byte)86, (byte)202, (byte)229, (byte)233, (byte)161};
    byte[] e = {1, 0, 1};
    byte[] d = {18, (byte)174, (byte)113, (byte)164, (byte)105, (byte)205, (byte)10, (byte)43, (byte)195, (byte)126, (byte)82, (byte)108, (byte)69, (byte)0, (byte)87, (byte)31, (byte)29, (byte)97, (byte)117, (byte)29, (byte)100, (byte)233, (byte)73, (byte)112, (byte)123, (byte)98, (byte)89, (byte)15, (byte)157, (byte)11, (byte)165, (byte)124, (byte)150, (byte)60, (byte)64, (byte)30, (byte)63, (byte)207, (byte)47, (byte)44, (byte)211, (byte)189, (byte)236, (byte)136, (byte)229, (byte)3, (byte)191, (byte)198, (byte)67, (byte)155, (byte)11, (byte)40, (byte)200, (byte)47, (byte)125, (byte)55, (byte)151, (byte)103, (byte)31, (byte)82, (byte)19, (byte)238, (byte)216, (byte)193, (byte)90, (byte)37, (byte)216, (byte)213, (byte)206, (byte)160, (byte)2, (byte)94, (byte)227, (byte)171, (byte)46, (byte)139, (byte)127, (byte)121, (byte)33, (byte)111, (byte)198, (byte)59, (byte)234, (byte)86, (byte)39, (byte)83, (byte)180, (byte)6, (byte)68, (byte)198, (byte)161, (byte)81, (byte)39, (byte)217, (byte)178, (byte)149, (byte)69, (byte)64, (byte)160, (byte)187, (byte)225, (byte)163, (byte)5, (byte)86, (byte)152, (byte)45, (byte)78, (byte)159, (byte)222, (byte)95, (byte)100, (byte)37, (byte)241, (byte)77, (byte)75, (byte)113, (byte)52, (byte)65, (byte)181, (byte)93, (byte)199, (byte)59, (byte)155, (byte)74, (byte)237, (byte)204, (byte)146, (byte)172, (byte)227, (byte)146, (byte)126, (byte)55, (byte)245, (byte)125, (byte)12, (byte)253, (byte)94, (byte)117, (byte)129, (byte)250, (byte)81, (byte)44, (byte)143, (byte)73, (byte)97, (byte)169, (byte)235, (byte)11, (byte)128, (byte)248, (byte)168, (byte)7, (byte)70, (byte)114, (byte)138, (byte)85, (byte)255, (byte)70, (byte)71, (byte)31, (byte)52, (byte)37, (byte)6, (byte)59, (byte)157, (byte)83, (byte)100, (byte)47, (byte)94, (byte)222, (byte)30, (byte)132, (byte)214, (byte)19, (byte)8, (byte)26, (byte)250, (byte)92, (byte)34, (byte)208, (byte)81, (byte)40, (byte)91, (byte)214, (byte)59, (byte)148, (byte)59, (byte)86, (byte)93, (byte)137, (byte)138, (byte)5, (byte)104, (byte)84, (byte)19, (byte)229, (byte)60, (byte)60, (byte)108, (byte)101, (byte)37, (byte)255, (byte)31, (byte)227, (byte)78, (byte)61, (byte)220, (byte)112, (byte)240, (byte)213, (byte)100, (byte)80, (byte)253, (byte)164, (byte)139, (byte)161, (byte)46, (byte)16, (byte)78, (byte)157, (byte)235, (byte)159, (byte)184, (byte)24, (byte)129, (byte)225, (byte)196, (byte)189, (byte)242, (byte)93, (byte)146, (byte)71, (byte)244, (byte)80, (byte)200, (byte)101, (byte)146, (byte)121, (byte)104, (byte)231, (byte)115, (byte)52, (byte)244, (byte)65, (byte)79, (byte)117, (byte)167, (byte)80, (byte)225, (byte)57, (byte)84, (byte)110, (byte)58, (byte)138, (byte)115, (byte)157};
    
    BigInteger N = new BigInteger(1, n);
    BigInteger E = new BigInteger(1, e);
    BigInteger D = new BigInteger(1, d);
    
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(N, E);
    RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(N, D);

    RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);
    RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(privKeySpec);
    
    String signed = jwt.serialize(privKey);
    String[] split = signed.split("\\.");
    
    assertEquals(3, split.length);
    assertEquals(jwtHeaderSegment, split[0]);
    String jwtPayloadSegment = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ";
    assertEquals(jwtPayloadSegment, split[1]);
    assertEquals(jwtCryptoSegment, split[2]);
    
    String expected = jwtHeaderSegment + "." + jwtPayloadSegment + "." + jwtCryptoSegment;
    assertEquals(expected, signed);

  }

  public void testRS256() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException, JSONException, IOException {
    String jwtHeaderSegment = "eyJhbGciOiJSUzI1NiJ9";
    String jwtCryptoSegment = "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw";
    testRSASHA(rs256, jwtHeaderSegment, jwtCryptoSegment);
  }
  
  public void testRS384() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException, JSONException, IOException {
    String jwtHeaderSegment = "eyJhbGciOiJSUzM4NCJ9";
    String jwtCryptoSegment = "UqgNjrJOGhk4wfoSG6Uvrt9GcKu-TgPwInExALrMBadg1pol1uTw7mZADTddAWsC6ZzdFiTFUmIi7DuD38ftLAZoW4qezdAO7RYf1yZDsbT20bt8DJJN1I4VovL2PLg80B6x6ug-kaW8k5LaM5ce0dk1zgWhjafKC3Mb4UNLL8f9fqVMkHpdWYRjF6QjTz12Ap-gq-tPyUoWSdvzCIYOcZ9-08SQQdUTTgsNF1Qwu3TqeWPqzNJwmWHiHMmaV8I4ktMFEX-AiEBa55KsfYTx0jSbTHP-odqmnLQJ4n-oQJ2RSXy0HQP6BkdiwDHdoMUk4z_wAeOsfDTs_mLxTgOInQ";
    testRSASHA(rs384, jwtHeaderSegment, jwtCryptoSegment);
  }

}
-->